package org.swift.mashup.engine.model;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.jfree.util.Log;

/**
 * @author jroberts
 * 
 * Executes an external program.
 * 
 * The activity is run inside a temp directory.  It lays down the context as a file called "input.txt".  
 * Parameters are put down as <paramname>.txt
 * 
 * the script must output all results to output.txt for the activity to pick it up and return the results.
 */
public class ScriptActivity implements Activity {

	private String script;

	private List<String> cmd = new ArrayList<String>();

	private File workingDir;
	
	
	public ScriptActivity(String script, List<String> cmd, File workingDir) {
		this.script = script;
		this.cmd.addAll(cmd);
		this.workingDir = workingDir;
	}

	@Override
	public ActivityResultComponent doActivity(ActivityContext context,
			Map<String, ?> parameters) throws ActivityException {

		try {
			File tempdir = org.swift.commons.util.io.FileUtils.createTempDirectory(workingDir);			
			File inputFile = new File(tempdir, "input.txt");
			FileUtils.writeByteArrayToFile(inputFile, context.getBytes());
			File scriptFile = new File(tempdir, "script.m");
			FileUtils.writeStringToFile(scriptFile, script);

			writeParameters(tempdir, parameters);
			
			ProcessBuilder processBuilder = new ProcessBuilder(this.cmd);
			processBuilder.directory(tempdir);
			Process p = processBuilder.start();			
			p.waitFor();			
			if (p.exitValue() != 0) {
				String error = IOUtils.toString(p.getErrorStream());
				throw new ActivityException("Script exited with error: " + error);
			}
			
			File outputFile = new File(tempdir, "output.txt");
			byte[] results = FileUtils.readFileToByteArray(outputFile);	
			try {
				FileUtils.forceDelete(tempdir);
			} catch (IOException e) {
				Log.warn("Could not cleanup temp directory: " + tempdir);
			}
			return new ActivityResultItem(results);
		} catch (IOException e) {
			throw new ActivityException(e);
		} catch (InterruptedException e) {
			throw new ActivityException("Error executing the script", e);
		}		
	}

	private void writeParameters(File tempdir,
			Map<String, ?> parameters) throws NotSupportedActivityException {
	
		for(Entry<String, ?> param : parameters.entrySet()) {
			File file = new File(tempdir, param.getKey() + ".txt");
			byte[] bytes = toBytes(param.getValue());
			try {
				FileUtils.writeByteArrayToFile(file, bytes);
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}

	private byte[] toBytes(Object value) throws NotSupportedActivityException {
		if (value instanceof byte[]) {
			return (byte[])value;
		} else if (value instanceof String) {
			return ((String)value).getBytes();
		} else {
			throw new NotSupportedActivityException(value.getClass().toString());
		}
	}

	

	protected String getScript() {
		return script;
	}

	protected List<String> getCmd() {
		return cmd;
	}

	protected File getWorkingDir() {
		return workingDir;
	}

}
